import { CostStrategyManager } from "GameLoop/Path/CostStrategyManager";

 
import { CacheOper } from "./CacheOperator";
import { ACostDecorate } from "./CostDecorate/ACostDecorate";
import { ACreepCrossPortal } from "./CostDecorate/ACreepCrossPortal";
import { ACreepNormalStructureBlock } from "./CostDecorate/ACreepNormalStructureBlock";
import { ACreepSetCreepBlock } from "./CostDecorate/ACreepSetCreepBlock";
import { ACreepSetDamageIngoreBlock } from "./CostDecorate/ACreepSetDamageIngoreBlock";
import { ACreepSetEludeHostile } from "./CostDecorate/ACreepSetEludeHostile";
import { ACreepSetForceBlock } from "./CostDecorate/ACreepSetForceBlock";
import { ACreepSetIngoreBlock } from "./CostDecorate/ACreepSetIngoreBlock";
import { setArmyBlock } from "./CostStrategy/roomCostStrategyOfTeam4";
import { UtilsHelper } from "utils/position/UtilsHelper";
import { ACreepStructurePlanBlock } from "./CostDecorate/ACreepStructurePlanBlock";
import { PositionHelper } from "utils/position/PositionHelper";
import { VisualHelper } from "utils/visual/visual";
import { ACreepRoadPlan } from "./CostDecorate/ACreepRoadPlan";
import { dangrous_style } from "utils/constants/globalconstant";
import { cpu_used } from "utils/decorate/decorate";


export interface ICostMap
{
    c_structure:ACreepNormalStructureBlock
    c_portal:ACreepCrossPortal
    c_creep:ACreepSetCreepBlock
    c_damage:ACreepSetDamageIngoreBlock
    c_elude:ACreepSetEludeHostile
    c_position:ACreepSetForceBlock
    c_ingore:ACreepSetIngoreBlock
    c_structureplan:ACreepStructurePlanBlock
    c_roadplan:ACreepRoadPlan

}
export type CostKeys = keyof ICostMap;
/**
 * 车站寻路模块，
 * 车站寻路只会寻找一个房间内的两个车站之间的路径
 */
export class PathFinderManager
{
    // @memory_cache(["pathcache"])
    public _blockCreeps!:Record<string,Record<string,boolean>>;     // 阻挡寻路的Creep
    // @memory_cache(["pathcache"])
    public _blockPosition!:{[key:string]:number[][]};
    private  _structureMatrix: { [key: string]:CostMatrix } = {};    // 建筑矩阵
    private _stationinstace!:IStationInterface;

    private _CostDecorate:Record<CostKeys,ICostMap[CostKeys]>={} as any;// cost 装饰器
    constructor(stationinstace:IStationInterface)
    {
        this._stationinstace = stationinstace;
        CostStrategyManager.init();
        if(!this._blockCreeps)
        {
            this._blockCreeps={};
        }
        if(!this._blockPosition)
        {
            this._blockPosition={};
        }
        this._CostDecorate["c_structureplan"] = new ACreepStructurePlanBlock();
        this._CostDecorate["c_structure"] = new ACreepNormalStructureBlock();
        this._CostDecorate["c_portal"] = new ACreepCrossPortal();
        this._CostDecorate["c_creep"] = new ACreepSetCreepBlock();
        this._CostDecorate["c_damage"] = new ACreepSetDamageIngoreBlock();
        this._CostDecorate["c_elude"] = new ACreepSetEludeHostile();
        this._CostDecorate["c_position"] = new ACreepSetForceBlock();
        this._CostDecorate["c_ingore"] = new ACreepSetIngoreBlock();
        this._CostDecorate["c_roadplan"] = new ACreepRoadPlan();

    }
    private get stationNet():IStationInterface
    {
        return this._stationinstace;
    }
    public RegisterBlockCreep(creep:Creep)
    {
         
        if(this._blockCreeps[creep.room.name])
        {
            this._blockCreeps[creep.room.name][ creep.name]=true;
        }
        else 
        {
            this._blockCreeps[creep.room.name]={
                [creep.name]:true
            }
        }
      
    }
    public UnRegisterBlockCreep(creep:Creep)
    {
        if(this._blockCreeps[creep.room.name])
        {
            delete this._blockCreeps[creep.room.name][ creep.name];
        }
      
    }
    public RegisterRoomBlockPosition(pos:RoomPosition)
    {
        let roomPositions =  this._blockPosition[pos.roomName];
        if(!roomPositions)
        {
            roomPositions=[];
            this._blockPosition[pos.roomName]=roomPositions;
        }
        const _this = this;
        const index =  _.findIndex( roomPositions,item=>{return item[0]==pos.x && item[1]==pos.y });
        if(index>=0)
        {
            return ;
        }
        roomPositions.push([pos.x,pos.y]);
    }
    public RegisterRoomMatrix(roomName:string,matrix:CostMatrix)
    {
        this._structureMatrix[roomName] = matrix;
    }


    public  getRoomMatrix(roomName:string):CostMatrix
    {
        return this._structureMatrix[roomName];
    }
    /**
     * 普通爬虫寻路
     * @param origin
     * @param goal
     * @param opt
     * @param decorates
     * @returns
     */
    public searchPathCache(origin: RoomPosition,goal: { pos: RoomPosition; range: number },opt:IPathFinderOpt,decorates:CostKeys[]=["c_structure","c_creep","c_position"] ): IPathCache
    {   
        // let avoidRooms = (this.stationNet as  any)._avoidRooms as Record<string,boolean>;
        if(!opt.IsIngoreRoute)
        {
            let  allowedRooms:{[key:string]:boolean}={} ;
            const route = this.stationNet.findRoute(origin.roomName,goal.pos.roomName,1);
            if(route)
            {
                for(const e of route.value.route)
                {
                    allowedRooms[e]=true;
                }
            }
            opt.route = Object.keys(allowedRooms);
        }
        
        const  pathResult = this.searchPath(origin,goal,opt,decorates);
        if(pathResult )
        {
            const pathcache =  UtilsHelper.serializePathResult(origin,pathResult);

            return pathcache;
        }
        throw new Error(`无法查找到路径:${JSON.stringify(origin)}->${JSON.stringify(goal)}`);
        // return undefined;
    }
    /**
     * 查找从origin 到 rooma-roomb 的出口位置的寻路,实时寻路无法缓存
     * @param origin 
     * @param goal 
     * @param opt 
     * @param decorates 
     * @returns 
     */
    public searchPathToExit(origin: RoomPosition,goal: {rooma:string,roomb:string},opt:IPathFinderOpt,decorates:CostKeys[]=["c_structure","c_creep","c_position"] ): IPathCache
    {
        const goals = PositionHelper.getExitPositionsBetweenRooms(goal.rooma,goal.roomb);
        if(!goals)
        {
            throw new Error(`无法查找到:${JSON.stringify(goal)}之间的出口坐标`);
        }
        const  pathResult = this.searchPath(origin,goals.map(e=>{
            return {pos:PositionHelper.Create(e),range:0}
        }),opt,decorates);
        if(pathResult )
        {
            const pathcache =  UtilsHelper.serializePathResult(origin,pathResult);

            return pathcache;
        }
        throw new Error(`无法查找到路径:${JSON.stringify(origin)}->${JSON.stringify(goal)}`);
        // return undefined;
    }
    /**
     * 修路坐标
     * @param origin
     * @param goal
     * @returns
     */
    public serachRoad(origin: RoomPosition,goal: { pos: RoomPosition; range: number },opt:IPathFinderOpt)
    {
        return this.searchPath(origin,goal,opt,["c_structureplan","c_roadplan","c_position"])
    }

    public searchPathOneRoom(origin: RoomPosition,goal:RoomPosition,opt:IPathFinderOpt,decorates:CostKeys[]): PathStep[]|false
    {  const _this = this;
        const room1 = Game.rooms[origin.roomName]
        // 房间没有视野
        if (!room1)
        {
            return false;
        }
        const pathResult = room1.findPath(origin, goal,{
            plainCost:opt.PathCost?.plainCost?opt.PathCost.plainCost: 2,
            swampCost:opt.PathCost?.swampCost?opt.PathCost.swampCost: 10,
            maxRooms:opt.maxRooms?opt.maxRooms:8,
            ignoreRoads:true,// road自己判断
            maxOps:4000,
            costCallback:(roomName: string, costMatrix: CostMatrix)=>{
                    // const room = Game.rooms[roomName];
                    if(opt.route && !opt.route.includes(roomName))
                    {
                        // 有路由配置但当前房间不在路由配置中
                        return  ;
                    }
                    let costs :CostMatrix = costMatrix;
                    if(opt.IsUseSafeRegion)
                    {
                        costs = CostStrategyManager.getPathCost("roomCostStrategyOfSafe",roomName);
                        //global.Log.Info(`[${roomName}] 使用安全寻路:${JSON.stringify(opt)}`);
                    }
                    else
                    {
                        costs = CostStrategyManager.getPathCost("roomCostStrategyOfCreepNormal",roomName);
                    }

                    for(const e of decorates)
                    {
                        costs= this._CostDecorate[e].decorate(this,roomName,costs,opt);
                    }
                    if(opt.route && opt.route.length>1)
                    {
                        // 补丁限制到route之外的房间。以后有其他的好办法再改
                        const exits =  Game.map.describeExits(roomName);
                        for(let k in exits)
                        {
                            if(exits[k as ExitKey] as string == goal.roomName ||opt.route.includes(exits[k as ExitKey] as string) )
                            {
                                continue;
                            }
                           
                            const exitposs = PositionHelper.getExitPositions(roomName,k as ExitKey);
                            for(const es of exitposs)
                            {
                                for(const p of es)
                                {
                                    costs.set(p.x,p.y,0xff);
                                 
                                }
                            }
                        }
                        
                    }
                    
                    
                return costs
            }
        });

        return pathResult;
    }
    public   searchPathOfCurrentRoom(origin: RoomPosition,goal:PathGoal,opt:IPathFinderOpt,decorates:CostKeys[]): PathFinderPath|false
    {

        const room1 = Game.rooms[origin.roomName]
                // 房间没有视野
        if (!room1)
        {
            return false;
        }
        const pathResult = PathFinder.search(origin, goal,{
            plainCost:opt.PathCost?.plainCost?opt.PathCost.plainCost: 2,
            swampCost:opt.PathCost?.swampCost?opt.PathCost.swampCost: 10,
            maxRooms:opt.maxRooms?opt.maxRooms:16,
            maxOps:1000,
            roomCallback:roomName=>{
                    const room = Game.rooms[roomName];
                    if(opt.route && !opt.route.includes(roomName))
                    {
                        // 有路由配置但当前房间不在路由配置中
                        return false;
                    }
                    let costs :CostMatrix;
                    if(opt.IsUseSafeRegion)
                    {
                        costs = CostStrategyManager.getPathCost("roomCostStrategyOfSafe",roomName);
                        //global.Log.Info(`[${roomName}] 使用安全寻路:${JSON.stringify(opt)}`);
                    }
                    else
                    {
                        costs = CostStrategyManager.getPathCost("roomCostStrategyOfCreepNormal",roomName);
                    }
                     
                    for(const e of decorates)
                    {
                        costs= this._CostDecorate[e].decorate(this,roomName,costs,opt);
                    }
                    
                return costs
            }
        });
        pathResult.path =  pathResult.path.filter(e=>e.roomName == origin.roomName)
        return pathResult;
    }
    public getMatrix(room:Room,issafe:boolean,decorates:CostKeys[],opt:{}={})
    {
        let costs :CostMatrix;
        if(issafe)
        {
            costs = CostStrategyManager.getPathCost("roomCostStrategyOfSafe",room.name);
            //global.Log.Info(`[${roomName}] 使用安全寻路:${JSON.stringify(opt)}`);
        }
        else
        {
            costs = CostStrategyManager.getPathCost("roomCostStrategyOfCreepNormal",room.name);
        }
        
        for(const e of decorates)
        {
            costs= this._CostDecorate[e].decorate(this,room.name,costs,opt);
        }
        return costs;
    }
   
    public   searchPath(origin: RoomPosition,goal:PathGoal,opt:IPathFinderOpt,decorates:CostKeys[]): PathFinderPath|false
    {
        const _this = this;
        const room1 = Game.rooms[origin.roomName]
                // 房间没有视野
        if (!room1)
        {
            return false;
        }
        // Path[0]是与起点相邻的坐标
        const pathResult = PathFinder.search(origin, goal,{
            plainCost:opt.PathCost?.plainCost?opt.PathCost.plainCost: 2,
            swampCost:opt.PathCost?.swampCost?opt.PathCost.swampCost: 10,
            maxRooms:opt.maxRooms?opt.maxRooms:8,
            maxOps:4000,
            roomCallback:roomName=>{
                    const room = Game.rooms[roomName];
                    if(opt.route && !opt.route.includes(roomName))
                    {
                        // 有路由配置但当前房间不在路由配置中
                        return false;
                    }
                    let costs :CostMatrix;
                    if(opt.IsUseSafeRegion)
                    {
                        costs = CostStrategyManager.getPathCost("roomCostStrategyOfSafe",roomName);
                        //global.Log.Info(`[${roomName}] 使用安全寻路:${JSON.stringify(opt)}`);
                    }
                    else
                    {
                        costs = CostStrategyManager.getPathCost("roomCostStrategyOfCreepNormal",roomName);
                    }
                    
                    for(const e of decorates)
                    {
                        costs= this._CostDecorate[e].decorate(this,roomName,costs,opt);
                    }
                    
                return costs
            }
        });

         return pathResult;
    }
    // 查找小队移动路径
    public searchArmyPath(origin: RoomPosition,goal: { pos: RoomPosition; range: number },blockPositions?:RoomPosition[], opt?:IPathFinderOpt): IPathCache
    {
        // const routeKey = `${this.standardizePos(origin)} ${this.standardizePos(goal.pos)}`
        let avoidRooms = (this.stationNet as  any)._avoidRooms as Record<string,boolean>;
        let  allowedRooms:{[key:string]:boolean}={} ;
        const route = this.stationNet.findRoute(origin.roomName,goal.pos.roomName,1);
        if(route)
        {
            for(const e of route.value.route)
            {
                allowedRooms[e]=true;
            }
        }

        const pathResult = PathFinder.search(origin, goal,{
            plainCost:2,
            swampCost:40,
            maxOps:opt?.maxOps?opt?.maxOps:2000,
            roomCallback:roomName=>{
                if( allowedRooms && allowedRooms[roomName] === undefined)
                {
                    return false;
                }
                // 强调了不许走就不走
                if (avoidRooms && avoidRooms[roomName]) return false
                let pathcost:CostMatrix;
                if(opt?.IsDestoryStructure)
                {
                    pathcost = CostStrategyManager.getPathCost("roomCostStrategyOfTeam4DestoryStructure",roomName);
                }
                else 
                {
                    pathcost = CostStrategyManager.getPathCost("roomCostStrategyOfTeam4",roomName);
                }
                
                
                // 1.寻路的禁止通行点
                if(blockPositions)
                {
                    for(const pos of blockPositions)
                    {
                        setArmyBlock(pathcost,pos.x,pos.y, 0xff);
                    }
                }
                if(Game.rooms[roomName])
                {
                    const blockposs = Game.rooms[roomName].getBlock();
                    for(const pos of blockposs)
                    {
                        setArmyBlock(pathcost,pos %50,Math.floor( pos/50), 0xff);
                    }
                }

                // 2.房间注册的阻挡点

                // 3.避开敌方高伤害单位
                if(opt?.ingoreDamage )
                {
                    const station = global.world.PollHostiles(roomName);
                    if(station )
                    {
                        for(let x in station.hostileDamageMap)
                        {
                            for(let y in station.hostileDamageMap[x])
                            {

                                if(station.hostileDamageMap[x][y]>=opt.ingoreDamage)
                                {
                                    pathcost.set(parseInt( x),parseInt(y),0xff);
                                }
                            }
                        }
                    }
                }
                return pathcost
            }
            });

            return UtilsHelper.serializePathResult(origin,pathResult)

    }

    visualDebugCost(room:Room,decorates:CostKeys[], opt:IPathFinderOpt)
    {
        let costs :CostMatrix;
        if(opt.IsUseSafeRegion)
        {
            costs = CostStrategyManager.getPathCost("roomCostStrategyOfSafe",room.name);
            //global.Log.Info(`[${roomName}] 使用安全寻路:${JSON.stringify(opt)}`);
        }
        else
        {
            costs = CostStrategyManager.getPathCost("roomCostStrategyOfCreepNormal",room.name);
        }
        const blockCreeps= this._blockCreeps[room.name];
        if(blockCreeps)
        {
            const keys = Object.keys(blockCreeps);
            for(let e of keys)
            {
                if(Game.creeps[e]  )
                {
                    costs.set(Game.creeps[e].pos.x,Game.creeps[e].pos.y,0xff);
                }
                else 
                {
                    delete blockCreeps[e];
                }
            }
        }
        //global.Log.Info(`[${room.name}] 阻挡寻路的爬名:${JSON.stringify( Object.keys(this._blockCreeps))}`);
        for(const e of decorates)
        {
            costs= this._CostDecorate[e].decorate(this,room.name,costs,opt);
        }
         VisualHelper.drawMatrix(room,costs);
    }
}
